# -*- coding: utf-8 -*-
# @Author  : longbhu
# @Time    : 2025/2/24 13:05
# @Function:
from typing import Union, Dict, List
import numpy as np


# 参数类，用于存储参数的名称、值、是否为矩阵、使用场景和描述
class Parameter:
    def __init__(self, name: str, value: Union[float, int, np.ndarray, Dict], is_matrix: bool,
                 used_in_formula: str, description: str, is_excel: bool, is_value_parameter: bool):
        self.name = name  # 参数名称
        self.value = value  # 参数值，可以是标量、NumPy 矩阵或字典
        self.is_matrix = is_matrix  # 是否为矩阵
        self.used_in_formula = used_in_formula  # 使用该参数的公式名称
        self.description = description  # 参数描述
        self.is_excel = is_excel  # 是否与 Excel 相关
        self.is_value_parameter = is_value_parameter  # 是否用于计算价值量

    def __repr__(self):
        return (f"Parameter(name={self.name!r}, value={self.value!r}, is_matrix={self.is_matrix!r}, "
                f"used_in_formula={self.used_in_formula!r}, description={self.description!r}, "
                f"is_excel={self.is_excel!r}, is_value_parameter={self.is_value_parameter!r})")


# param1 = Parameter(name="alpha", value=0.5, is_matrix=False,
#                    used_in_formula="Formula1", description="Alpha value", is_excel=False)
# print(param1)

# 公式类，用于存储公式的名称、表达式、所需参数和适用模式
class Formula:
    def __init__(
            self,
            name: str,
            expression: str,  # 公式表达式
            required_params: List[Dict[str, Union[str, bool]]],  # 所需参数及其是否为矩阵
            applicable_ecosystems: list,
            mode: str = None,  # 可选的计算模式
    ):
        self.name = name
        self.expression = expression
        self.required_params = required_params  # 参数需求列表
        self.applicable_ecosystems = applicable_ecosystems  # 该公式用于哪些生态系统类型中
        self.mode = mode

    def __repr__(self):
        return (f"Formula(name={self.name!r}, expression={self.expression!r}, "
                f"required_params={self.required_params!r}, "
                f"applicable_ecosystems={self.applicable_ecosystems!r}, mode={self.mode!r})")


# 参数管理器类，用于添加和获取参数
class ParameterManager:
    def __init__(self):
        self.parameters = {}  # 参数字典

    def add_parameter(self, param: Parameter):
        self.parameters[param.name] = param

    def get_param(self, name: str) -> Union[Parameter, None]:
        return self.parameters.get(name)

    # 从 JSON 文件加载参数


# 公式匹配器类，用于根据当前模式和已有参数获取可用公式
class FormulaMatcher:
    def __init__(self, formulas: List[Formula], param_manager: ParameterManager):
        self.formulas = formulas
        self.param_manager = param_manager

    # todo mode 修改成代表调节服务的每项服务
    def get_available_formulas(self, current_mode: str = None) -> tuple[list[Formula], list[str | bool]]:
        available = []
        formula_excel_name = []
        for formula in self.formulas:
            # 检查模式是否匹配（如果需要）
            if current_mode and formula.mode and formula.mode != current_mode:
                continue

            # 检查参数是否存在且类型正确
            params_met = True
            for req_param in formula.required_params:
                param = self.param_manager.get_param(req_param["name"])
                if not param:
                    params_met = False
                    break

                # 检查参数的 is_matrix 属性是否匹配
                if param.is_matrix != req_param.get("is_matrix", False):
                    params_met = False
                    break

                # 检查参数的 is_excel 属性是否匹配（如果需要）
                if req_param.get("is_excel") is not None and param.is_excel != req_param["is_excel"]:
                    params_met = False
                    formula_excel_name.append(req_param["name"])
                    break

                # 检查参数的 is_value_parameter 属性是否匹配（如果需要）
                if req_param.get("is_value_parameter") is not None and param.is_value_parameter != req_param[
                    "is_value_parameter"]:
                    params_met = False
                    break

            if params_met:
                available.append(formula)

        return available,formula_excel_name


# 矩阵计算器类，负责参数管理和公式计算
class MatrixCalculator:
    def __init__(self):
        self.param_manager = ParameterManager()
        self.formulas = []  # 公式列表
        self.current_mode = None  # 当前计算模式

    def load_formulas(self, formulas: List[Formula]):
        self.formulas.extend(formulas)

    def set_mode(self, mode: str):
        self.current_mode = mode

    def prompt_available_formulas(self) -> tuple[list[str], list[str | bool]]:
        matcher = FormulaMatcher(self.formulas, self.param_manager)
        available,formula_excel_name = matcher.get_available_formulas(self.current_mode)
        return [f.name for f in available], formula_excel_name

    # todo 可能需要在这里乘上生态图矩阵，或者在这个返回的结果去乘上生态图矩阵
    def execute_formula(self, formula_name: str) -> Union[float, np.ndarray]:
        formula = next(f for f in self.formulas if f.name == formula_name)
        params = {}
        for req_param in formula.required_params:
            param = self.param_manager.get_param(req_param["name"])
            params[req_param["name"]] = param.value

        result = eval(formula.expression, {}, params)  # 传递一个空的全局变量字典 {}，避免 eval 访问全局变量。
        return result

        # 执行计算
        # if formula_name == "Ept":
        #     lcr_epp = params["lcr_epp"]
        #     lcr_s = params["lcr_s"]
        #     lcr_d = params["lcr_d"]
        #     lcr_r = params["lcr_r"]
        #     # result = lcr_epp * lcr_s * lcr_d * 1e6 / (3600 * lcr_r) # todo 应该使用ept_formula中的expression，而不是重写一遍公式。会产生公式不统一的风险。
        #     # 使用 eval 动态解析和执行公式字符串。
        #     result = eval(formula.expression, {}, params) # 传递一个空的全局变量字典 {}，避免 eval 访问全局变量。
        #     return result
        # else:
        #     raise NotImplementedError("Formula not implemented")
